#include "Baller.hpp"
#include<cmath>
#include "ArenaRoom.hpp"
#include "GameSetting.hpp"
using namespace std;

Baller::Baller(TcpConnectorPtr connPtr,BallerID id,string name,ProtoMsg::Color color):
	_conn(connPtr)
{
	printf("Baller id = %lu name = %s construct\n",id,name.c_str());
    _userInfo.set_userid(id);
    _userInfo.set_username(name);
    _userInfo.set_roomid(-1);

    _ballState.set_ballerid(id);
	_ballState.set_color(color);
}

Baller::~Baller()
{
	printf("Baller id = %lu name = %s destruct\n",_userInfo.userid(),_userInfo.username().c_str());
}

void Baller::fillBallInfo(ProtoMsg::Dto_Baller* ballInfo)
{
    if(ballInfo == nullptr)return;
    ballInfo->CopyFrom(_ballState);
}

void Baller::fillUserInfo(ProtoMsg::UserInfo* userInfo)
{
    if(userInfo == nullptr)return;
    userInfo->CopyFrom(_userInfo);
}

void Baller::SendPacket(const ProtoMsg::Packet& packet)
{
	int32_t payloadSize = packet.ByteSize();
	int32_t totalSize = payloadSize + 4;
	unique_ptr<char> netDataPtr(new char[totalSize]);
	memcpy(&netDataPtr.get()[0],&payloadSize,4);
	packet.SerializeToArray(&netDataPtr.get()[4],payloadSize);

	auto tcpConn = _conn.lock();
	if(tcpConn != nullptr)
	{
		tcpConn->SendData(netDataPtr.get(),totalSize);
	}
}
void Baller::InitBallerState()
{
    ResetBallerState();
    float posx = rand()%10000;
    float posy = rand()%10000;
    _ballState.mutable_curpos()->set_x(posx);
    _ballState.mutable_curpos()->set_y(posy);
    printf("id = %lu 初始化状态\n",_ballState.ballerid());
}

void Baller::ResetBallerState()
{
	_ballState.clear_weight();
	_ballState.clear_curpos();
	_ballState.clear_curvec();
	_ballState.clear_color();
}

	//todo 检查边界
void Baller::checkBorder()
{
	if(_ballState.curpos().x() >= MAP_MAX_X)
	{
		_ballState.mutable_curpos()->set_x(MAP_MAX_X);
	}
	else if(_ballState.curpos().x() <= MAP_MIN_X)
	{
		_ballState.mutable_curpos()->set_x(MAP_MIN_Y);
	}

	if(_ballState.curpos().y() >= MAP_MAX_Y)
	{
		_ballState.mutable_curpos()->set_y(MAP_MAX_Y);
	}
	else if(_ballState.curpos().y() <= MAP_MIN_Y)
	{
		_ballState.mutable_curpos()->set_y(MAP_MIN_Y);
	}
};

void Baller::calcPosition(const ProtoMsg::BallerMove& move,int64_t ms)
{
    //更新方向
    _ballState.mutable_curvec()->set_xvec(move.vec().xvec());
    _ballState.mutable_curvec()->set_yvec(move.vec().yvec());

	float cur_x = _ballState.curpos().x();
	float cur_y = _ballState.curpos().y();
	float cur_sped = Ball_PER_SEC_SPED * (ms/1000.0f);
	cur_x += _ballState.curvec().xvec() * cur_sped;
	cur_y += _ballState.curvec().yvec() * cur_sped;
	_ballState.mutable_curpos()->set_x(cur_x);
	_ballState.mutable_curpos()->set_y(cur_y);

	checkBorder();
}

bool Baller::canEat(float foodx, float foody)
{
	float weight = _ballState.weight();
	
	float ballx = _ballState.curpos().x();
	float bally = _ballState.curpos().y();

	float distance = sqrt(pow(ballx - foodx, 2) + pow(bally - foody, 2));
	if(distance <= weight)
	{
		return true;
	}
	return false;
}

void Baller::addWeight(float kg)
{
	float cur_weight = _ballState.weight();
	_ballState.set_weight(cur_weight+kg);
}

void Baller::eatFood(const ProtoMsg::BallerEat &eat)
{
	uint32_t roomid = _userInfo.roomid();
	ArenaRoomPtr roomPtr = ArenaRoomMgr::GetInstance().QueryRoom(roomid);
	if(!roomPtr)
	{
		return;
	}

	auto foodMgr = roomPtr->GetFoodMgr();
	for (int i = 0; i < eat.foodid_size(); i++)
	{
		FOOD_ID id = eat.foodid(i);
		Food one;
		if (!foodMgr.GetFood(id, one)) continue;
		if (!canEat(one.x, one.y)) continue;
		
		foodMgr.EatFood(id);
		addWeight(FOOD_WEIGHT);
	}
}

void Baller::SaveOperation(const ProtoMsg::BallerOperation& operation)
{
    _currOperation.CopyFrom(operation);
}
void Baller::HandleOperation(int64_t ms)
{//计算出当前玩家状态
    switch ((int)_currOperation.type())
    {
        case ProtoMsg::MOVE:
            calcPosition(_currOperation.move(),ms);
            break;
        case ProtoMsg::EAT:
            eatFood(_currOperation.eat());
            break;
        case ProtoMsg::DIVISION:
            break;
        case ProtoMsg::SPIT:
            break;
    }
}

//-------------------------------------------
BallerMgr* BallerMgr::Instance = nullptr;
uint64_t BallerMgr::BallerIDIndex = 0;
BallerMgr& BallerMgr::GetInstance()
{
    if(Instance == nullptr)
    {
        Instance = new BallerMgr();
    }
    return *Instance;
}

Baller* BallerMgr::CreateBaller(TcpConnectorPtr connPtr,string name,ProtoMsg::Color color)
{
	uint64_t newBallerID = BallerIDIndex++;
	Baller* newBallerPtr = new Baller(connPtr,newBallerID,name,color);
	BallerDict[newBallerID] = newBallerPtr;
	return newBallerPtr;
}

Baller* BallerMgr::QueryBaller(BallerID id)
{
	auto BallerIter = BallerDict.find(id);
	if(BallerIter != BallerDict.end())
	{
		return BallerIter->second;
	}
	return nullptr;
}

void BallerMgr::RemoveBaller(BallerID id)
{
	auto BallerIter = BallerDict.find(id);
	if(BallerIter != BallerDict.end())
	{
		Baller* pBaller = BallerIter->second;
		BallerDict.erase(BallerIter);
		delete pBaller;
	}
}

void BallerMgr::RemoveBaller(Baller* baller)
{
	RemoveBaller(baller->ID());
}


bool BallerMgr::ExistBaller(BallerID id)
{
	auto BallerIter = BallerDict.find(id);
	if(BallerIter != BallerDict.end())
	{
		return true;
	}
	return false;
}
